1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  package sun.java2d;
27  
28  import java.awt.Graphics;
29  import java.awt.Graphics2D;
30  import java.awt.RenderingHints;
31  import java.awt.RenderingHints.Key;
32  import java.awt.geom.Area;
33  import java.awt.geom.AffineTransform;
34  import java.awt.geom.NoninvertibleTransformException;
35  import java.awt.AlphaComposite;
36  import java.awt.BasicStroke;
37  import java.awt.image.BufferedImage;
38  import java.awt.image.BufferedImageOp;
39  import java.awt.image.RenderedImage;
40  import java.awt.image.renderable.RenderableImage;
41  import java.awt.image.renderable.RenderContext;
42  import java.awt.image.AffineTransformOp;
43  import java.awt.image.Raster;
44  import java.awt.image.WritableRaster;
45  import java.awt.Image;
46  import java.awt.Composite;
47  import java.awt.Color;
48  import java.awt.image.ColorModel;
49  import java.awt.GraphicsConfiguration;
50  import java.awt.Paint;
51  import java.awt.GradientPaint;
52  import java.awt.LinearGradientPaint;
53  import java.awt.RadialGradientPaint;
54  import java.awt.TexturePaint;
55  import java.awt.geom.Rectangle2D;
56  import java.awt.geom.PathIterator;
57  import java.awt.geom.GeneralPath;
58  import java.awt.Shape;
59  import java.awt.Stroke;
60  import java.awt.FontMetrics;
61  import java.awt.Rectangle;
62  import java.text.AttributedCharacterIterator;
63  import java.awt.Font;
64  import java.awt.image.ImageObserver;
65  import java.awt.Transparency;
66  import java.awt.font.GlyphVector;
67  import java.awt.font.TextLayout;
68  import sun.font.FontDesignMetrics;
69  import sun.font.FontUtilities;
70  import sun.java2d.pipe.PixelDrawPipe;
71  import sun.java2d.pipe.PixelFillPipe;
72  import sun.java2d.pipe.ShapeDrawPipe;
73  import sun.java2d.pipe.ValidatePipe;
74  import sun.java2d.pipe.ShapeSpanIterator;
75  import sun.java2d.pipe.Region;
76  import sun.java2d.pipe.TextPipe;
77  import sun.java2d.pipe.DrawImagePipe;
78  import sun.java2d.pipe.LoopPipe;
79  import sun.java2d.loops.FontInfo;
80  import sun.java2d.loops.RenderLoops;
81  import sun.java2d.loops.CompositeType;
82  import sun.java2d.loops.SurfaceType;
83  import sun.java2d.loops.Blit;
84  import sun.java2d.loops.MaskFill;
85  import sun.font.FontManager;
86  import java.awt.font.FontRenderContext;
87  import sun.java2d.loops.XORComposite;
88  import sun.awt.ConstrainableGraphics;
89  import sun.awt.SunHints;
90  import java.util.Map;
91  import java.util.Iterator;
92  import sun.java2d.DestSurfaceProvider;
93  import sun.misc.PerformanceLogger;
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 public final class SunGraphics2D
105     extends Graphics2D
106     implements ConstrainableGraphics, Cloneable, DestSurfaceProvider
107 {
108     
109 
110 
111     
112     public static final int PAINT_CUSTOM       = 6; 
113     public static final int PAINT_TEXTURE      = 5; 
114     public static final int PAINT_RAD_GRADIENT = 4; 
115     public static final int PAINT_LIN_GRADIENT = 3; 
116     public static final int PAINT_GRADIENT     = 2; 
117     public static final int PAINT_ALPHACOLOR   = 1; 
118     public static final int PAINT_OPAQUECOLOR  = 0; 
119 
120     
121     public static final int COMP_CUSTOM = 3;
122     public static final int COMP_XOR    = 2;
123     public static final int COMP_ALPHA  = 1;
124     public static final int COMP_ISCOPY = 0;
125 
126 
127 
128 
129 
130     
131     public static final int STROKE_CUSTOM = 3; 
132     public static final int STROKE_WIDE   = 2; 
133     public static final int STROKE_THINDASHED   = 1; 
134     public static final int STROKE_THIN   = 0; 
135 
136     
137     public static final int TRANSFORM_GENERIC = 4; 
138     public static final int TRANSFORM_TRANSLATESCALE = 3; 
139     public static final int TRANSFORM_ANY_TRANSLATE = 2; 
140     public static final int TRANSFORM_INT_TRANSLATE = 1; 
141     public static final int TRANSFORM_ISIDENT = 0; 
142 
143     
144     public static final int CLIP_SHAPE       = 2; 
145     public static final int CLIP_RECTANGULAR = 1; 
146     public static final int CLIP_DEVICE      = 0; 
147 
148     
149     public int eargb;  
150     public int pixel;  
151 
152     public SurfaceData surfaceData;
153 
154     public PixelDrawPipe drawpipe;
155     public PixelFillPipe fillpipe;
156     public DrawImagePipe imagepipe;
157     public ShapeDrawPipe shapepipe;
158     public TextPipe textpipe;
159     public MaskFill alphafill;
160 
161     public RenderLoops loops;
162 
163     public CompositeType imageComp;     
164 
165     public int paintState;
166     public int compositeState;
167     public int strokeState;
168     public int transformState;
169     public int clipState;
170 
171     public Color foregroundColor;
172     public Color backgroundColor;
173 
174     public AffineTransform transform;
175     public int transX;
176     public int transY;
177 
178     protected static final Stroke defaultStroke = new BasicStroke();
179     protected static final Composite defaultComposite = AlphaComposite.SrcOver;
180     private static final Font defaultFont =
181         new Font(Font.DIALOG, Font.PLAIN, 12);
182 
183     public Paint paint;
184     public Stroke stroke;
185     public Composite composite;
186     protected Font font;
187     protected FontMetrics fontMetrics;
188 
189     public int renderHint;
190     public int antialiasHint;
191     public int textAntialiasHint;
192     private int fractionalMetricsHint;
193 
194     
195     public int lcdTextContrast;
196     private static int lcdTextContrastDefaultValue = 140;
197 
198     private int interpolationHint;      
199     public int strokeHint;
200 
201     public int interpolationType;       
202                                         
203 
204     public RenderingHints hints;
205 
206     public Region constrainClip;                
207     public int constrainX;
208     public int constrainY;
209 
210     public Region clipRegion;
211     public Shape usrClip;
212     protected Region devClip;           
213 
214     
215     private boolean validFontInfo;
216     private FontInfo fontInfo;
217     private FontInfo glyphVectorFontInfo;
218     private FontRenderContext glyphVectorFRC;
219 
220     private final static int slowTextTransformMask =
221                             AffineTransform.TYPE_GENERAL_TRANSFORM
222                         |   AffineTransform.TYPE_MASK_ROTATION
223                         |   AffineTransform.TYPE_FLIP;
224 
225     static {
226         if (PerformanceLogger.loggingEnabled()) {
227             PerformanceLogger.setTime("SunGraphics2D static initialization");
228         }
229     }
230 
231     public SunGraphics2D(SurfaceData sd, Color fg, Color bg, Font f) {
232         surfaceData = sd;
233         foregroundColor = fg;
234         backgroundColor = bg;
235 
236         transform = new AffineTransform();
237         stroke = defaultStroke;
238         composite = defaultComposite;
239         paint = foregroundColor;
240 
241         imageComp = CompositeType.SrcOverNoEa;
242 
243         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
244         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
245         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
246         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
247         lcdTextContrast = lcdTextContrastDefaultValue;
248         interpolationHint = -1;
249         strokeHint = SunHints.INTVAL_STROKE_DEFAULT;
250 
251         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
252 
253         validateColor();
254 
255         font = f;
256         if (font == null) {
257             font = defaultFont;
258         }
259 
260         setDevClip(sd.getBounds());
261         invalidatePipe();
262     }
263 
264     protected Object clone() {
265         try {
266             SunGraphics2D g = (SunGraphics2D) super.clone();
267             g.transform = new AffineTransform(this.transform);
268             if (hints != null) {
269                 g.hints = (RenderingHints) this.hints.clone();
270             }
271             
272 
273 
274 
275 
276 
277             if (this.fontInfo != null) {
278                 if (this.validFontInfo) {
279                     g.fontInfo = (FontInfo)this.fontInfo.clone();
280                 } else {
281                     g.fontInfo = null;
282                 }
283             }
284             if (this.glyphVectorFontInfo != null) {
285                 g.glyphVectorFontInfo =
286                     (FontInfo)this.glyphVectorFontInfo.clone();
287                 g.glyphVectorFRC = this.glyphVectorFRC;
288             }
289             
290             return g;
291         } catch (CloneNotSupportedException e) {
292         }
293         return null;
294     }
295 
296     
297 
298 
299     public Graphics create() {
300         return (Graphics) clone();
301     }
302 
303     public void setDevClip(int x, int y, int w, int h) {
304         Region c = constrainClip;
305         if (c == null) {
306             devClip = Region.getInstanceXYWH(x, y, w, h);
307         } else {
308             devClip = c.getIntersectionXYWH(x, y, w, h);
309         }
310         validateCompClip();
311     }
312 
313     public void setDevClip(Rectangle r) {
314         setDevClip(r.x, r.y, r.width, r.height);
315     }
316 
317     
318 
319 
320 
321 
322 
323 
324 
325 
326 
327 
328 
329     public void constrain(int x, int y, int w, int h) {
330         if ((x|y) != 0) {
331             translate(x, y);
332         }
333         if (transformState >= TRANSFORM_TRANSLATESCALE) {
334             clipRect(0, 0, w, h);
335             return;
336         }
337         x = constrainX = transX;
338         y = constrainY = transY;
339         w = Region.dimAdd(x, w);
340         h = Region.dimAdd(y, h);
341         Region c = constrainClip;
342         if (c == null) {
343             c = Region.getInstanceXYXY(x, y, w, h);
344         } else {
345             c = c.getIntersectionXYXY(x, y, w, h);
346             if (c == constrainClip) {
347                 
348                 return;
349             }
350         }
351         constrainClip = c;
352         if (!devClip.isInsideQuickCheck(c)) {
353             devClip = devClip.getIntersection(c);
354             validateCompClip();
355         }
356     }
357 
358     protected static ValidatePipe invalidpipe = new ValidatePipe();
359 
360     
361 
362 
363     protected void invalidatePipe() {
364         drawpipe = invalidpipe;
365         fillpipe = invalidpipe;
366         shapepipe = invalidpipe;
367         textpipe = invalidpipe;
368         imagepipe = invalidpipe;
369         loops = null;
370     }
371 
372     public void validatePipe() {
373         surfaceData.validatePipe(this);
374     }
375 
376     
377 
378 
379 
380 
381 
382 
383     Shape intersectShapes(Shape s1, Shape s2, boolean keep1, boolean keep2) {
384         if (s1 instanceof Rectangle && s2 instanceof Rectangle) {
385             return ((Rectangle) s1).intersection((Rectangle) s2);
386         }
387         if (s1 instanceof Rectangle2D) {
388             return intersectRectShape((Rectangle2D) s1, s2, keep1, keep2);
389         } else if (s2 instanceof Rectangle2D) {
390             return intersectRectShape((Rectangle2D) s2, s1, keep2, keep1);
391         }
392         return intersectByArea(s1, s2, keep1, keep2);
393     }
394 
395     
396 
397 
398 
399 
400 
401 
402     Shape intersectRectShape(Rectangle2D r, Shape s,
403                              boolean keep1, boolean keep2) {
404         if (s instanceof Rectangle2D) {
405             Rectangle2D r2 = (Rectangle2D) s;
406             Rectangle2D outrect;
407             if (!keep1) {
408                 outrect = r;
409             } else if (!keep2) {
410                 outrect = r2;
411             } else {
412                 outrect = new Rectangle2D.Float();
413             }
414             double x1 = Math.max(r.getX(), r2.getX());
415             double x2 = Math.min(r.getX()  + r.getWidth(),
416                                  r2.getX() + r2.getWidth());
417             double y1 = Math.max(r.getY(), r2.getY());
418             double y2 = Math.min(r.getY()  + r.getHeight(),
419                                  r2.getY() + r2.getHeight());
420 
421             if (((x2 - x1) < 0) || ((y2 - y1) < 0))
422                 
423                 outrect.setFrameFromDiagonal(0, 0, 0, 0);
424             else
425                 outrect.setFrameFromDiagonal(x1, y1, x2, y2);
426             return outrect;
427         }
428         if (r.contains(s.getBounds2D())) {
429             if (keep2) {
430                 s = cloneShape(s);
431             }
432             return s;
433         }
434         return intersectByArea(r, s, keep1, keep2);
435     }
436 
437     protected static Shape cloneShape(Shape s) {
438         return new GeneralPath(s);
439     }
440 
441     
442 
443 
444 
445 
446 
447 
448 
449 
450     Shape intersectByArea(Shape s1, Shape s2, boolean keep1, boolean keep2) {
451         Area a1, a2;
452 
453         
454         
455         if (!keep1 && (s1 instanceof Area)) {
456             a1 = (Area) s1;
457         } else if (!keep2 && (s2 instanceof Area)) {
458             a1 = (Area) s2;
459             s2 = s1;
460         } else {
461             a1 = new Area(s1);
462         }
463 
464         if (s2 instanceof Area) {
465             a2 = (Area) s2;
466         } else {
467             a2 = new Area(s2);
468         }
469 
470         a1.intersect(a2);
471         if (a1.isRectangular()) {
472             return a1.getBounds();
473         }
474 
475         return a1;
476     }
477 
478     
479 
480 
481 
482     public Region getCompClip() {
483         if (!surfaceData.isValid()) {
484             
485             revalidateAll();
486         }
487 
488         return clipRegion;
489     }
490 
491     public Font getFont() {
492         if (font == null) {
493             font = defaultFont;
494         }
495         return font;
496     }
497 
498     private static final double[] IDENT_MATRIX = {1, 0, 0, 1};
499     private static final AffineTransform IDENT_ATX =
500         new AffineTransform();
501 
502     private static final int MINALLOCATED = 8;
503     private static final int TEXTARRSIZE = 17;
504     private static double[][] textTxArr = new double[TEXTARRSIZE][];
505     private static AffineTransform[] textAtArr =
506         new AffineTransform[TEXTARRSIZE];
507 
508     static {
509         for (int i=MINALLOCATED;i<TEXTARRSIZE;i++) {
510           textTxArr[i] = new double [] {i, 0, 0, i};
511           textAtArr[i] = new AffineTransform( textTxArr[i]);
512         }
513     }
514 
515     
516     public FontInfo checkFontInfo(FontInfo info, Font font,
517                                   FontRenderContext frc) {
518         
519 
520 
521 
522         if (info == null) {
523             info = new FontInfo();
524         }
525 
526         float ptSize = font.getSize2D();
527         int txFontType;
528         AffineTransform devAt, textAt=null;
529         if (font.isTransformed()) {
530             textAt = font.getTransform();
531             textAt.scale(ptSize, ptSize);
532             txFontType = textAt.getType();
533             info.originX = (float)textAt.getTranslateX();
534             info.originY = (float)textAt.getTranslateY();
535             textAt.translate(-info.originX, -info.originY);
536             if (transformState >= TRANSFORM_TRANSLATESCALE) {
537                 transform.getMatrix(info.devTx = new double[4]);
538                 devAt = new AffineTransform(info.devTx);
539                 textAt.preConcatenate(devAt);
540             } else {
541                 info.devTx = IDENT_MATRIX;
542                 devAt = IDENT_ATX;
543             }
544             textAt.getMatrix(info.glyphTx = new double[4]);
545             double shearx = textAt.getShearX();
546             double scaley = textAt.getScaleY();
547             if (shearx != 0) {
548                 scaley = Math.sqrt(shearx * shearx + scaley * scaley);
549             }
550             info.pixelHeight = (int)(Math.abs(scaley)+0.5);
551         } else {
552             txFontType = AffineTransform.TYPE_IDENTITY;
553             info.originX = info.originY = 0;
554             if (transformState >= TRANSFORM_TRANSLATESCALE) {
555                 transform.getMatrix(info.devTx = new double[4]);
556                 devAt = new AffineTransform(info.devTx);
557                 info.glyphTx = new double[4];
558                 for (int i = 0; i < 4; i++) {
559                     info.glyphTx[i] = info.devTx[i] * ptSize;
560                 }
561                 textAt = new AffineTransform(info.glyphTx);
562                 double shearx = transform.getShearX();
563                 double scaley = transform.getScaleY();
564                 if (shearx != 0) {
565                     scaley = Math.sqrt(shearx * shearx + scaley * scaley);
566                 }
567                 info.pixelHeight = (int)(Math.abs(scaley * ptSize)+0.5);
568             } else {
569                 
570 
571 
572 
573 
574 
575 
576 
577                 int pszInt = (int)ptSize;
578                 if (ptSize == pszInt &&
579                     pszInt >= MINALLOCATED && pszInt < TEXTARRSIZE) {
580                     info.glyphTx = textTxArr[pszInt];
581                     textAt = textAtArr[pszInt];
582                     info.pixelHeight = pszInt;
583                 } else {
584                     info.pixelHeight = (int)(ptSize+0.5);
585                 }
586                 if (textAt == null) {
587                     info.glyphTx = new double[] {ptSize, 0, 0, ptSize};
588                     textAt = new AffineTransform(info.glyphTx);
589                 }
590 
591                 info.devTx = IDENT_MATRIX;
592                 devAt = IDENT_ATX;
593             }
594         }
595 
596         info.font2D = FontUtilities.getFont2D(font);
597 
598         int fmhint = fractionalMetricsHint;
599         if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) {
600             fmhint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
601         }
602         info.lcdSubPixPos = false; 
603 
604         
605 
606 
607 
608 
609 
610 
611 
612 
613 
614 
615 
616 
617 
618 
619 
620 
621 
622 
623 
624 
625 
626         int aahint;
627         if (frc == null) {
628             aahint = textAntialiasHint;
629         } else {
630             aahint = ((SunHints.Value)frc.getAntiAliasingHint()).getIndex();
631         }
632         if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT) {
633             if (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
634                 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
635             } else {
636                 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;
637             }
638         } else {
639             
640 
641 
642 
643 
644 
645             if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP) {
646                 if (info.font2D.useAAForPtSize(info.pixelHeight)) {
647                     aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
648                 } else {
649                     aahint = SunHints.INTVAL_TEXT_ANTIALIAS_OFF;
650                 }
651             } else if (aahint >= SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB) {
652                 
653 
654 
655 
656 
657 
658 
659 
660 
661 
662 
663 
664 
665 
666 
667                 if (
668                     !surfaceData.canRenderLCDText(this)
669 
670 
671 
672                       ) {
673                     aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
674                 } else {
675                     info.lcdRGBOrder = true;
676                     
677 
678 
679 
680 
681 
682 
683                     if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HBGR) {
684                         aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;
685                         info.lcdRGBOrder = false;
686                     } else if
687                         (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VBGR) {
688                         aahint = SunHints.INTVAL_TEXT_ANTIALIAS_LCD_VRGB;
689                         info.lcdRGBOrder = false;
690                     }
691                     
692 
693 
694                     info.lcdSubPixPos =
695                         fmhint == SunHints.INTVAL_FRACTIONALMETRICS_ON &&
696                         aahint == SunHints.INTVAL_TEXT_ANTIALIAS_LCD_HRGB;
697                 }
698             }
699         }
700         info.aaHint = aahint;
701         info.fontStrike = info.font2D.getStrike(font, devAt, textAt,
702                                                 aahint, fmhint);
703         return info;
704     }
705 
706     public static boolean isRotated(double [] mtx) {
707         if ((mtx[0] == mtx[3]) &&
708             (mtx[1] == 0.0) &&
709             (mtx[2] == 0.0) &&
710             (mtx[0] > 0.0))
711         {
712             return false;
713         }
714 
715         return true;
716     }
717 
718     public void setFont(Font font) {
719         
720 
721 
722 
723 
724         if (font != null && font!=this.font) {
725             
726 
727 
728 
729 
730 
731 
732 
733 
734 
735 
736 
737 
738 
739             if (textAntialiasHint == SunHints.INTVAL_TEXT_ANTIALIAS_GASP &&
740                 textpipe != invalidpipe &&
741                 (transformState > TRANSFORM_ANY_TRANSLATE ||
742                  font.isTransformed() ||
743                  fontInfo == null || 
744                  (fontInfo.aaHint == SunHints.INTVAL_TEXT_ANTIALIAS_ON) !=
745                      FontUtilities.getFont2D(font).
746                          useAAForPtSize(font.getSize()))) {
747                 textpipe = invalidpipe;
748             }
749             this.font = font;
750             this.fontMetrics = null;
751             this.validFontInfo = false;
752         }
753     }
754 
755     public FontInfo getFontInfo() {
756         if (!validFontInfo) {
757             this.fontInfo = checkFontInfo(this.fontInfo, font, null);
758             validFontInfo = true;
759         }
760         return this.fontInfo;
761     }
762 
763     
764     public FontInfo getGVFontInfo(Font font, FontRenderContext frc) {
765         if (glyphVectorFontInfo != null &&
766             glyphVectorFontInfo.font == font &&
767             glyphVectorFRC == frc) {
768             return glyphVectorFontInfo;
769         } else {
770             glyphVectorFRC = frc;
771             return glyphVectorFontInfo =
772                 checkFontInfo(glyphVectorFontInfo, font, frc);
773         }
774     }
775 
776     public FontMetrics getFontMetrics() {
777         if (this.fontMetrics != null) {
778             return this.fontMetrics;
779         }
780         
781         return this.fontMetrics =
782            FontDesignMetrics.getMetrics(font, getFontRenderContext());
783     }
784 
785     public FontMetrics getFontMetrics(Font font) {
786         if ((this.fontMetrics != null) && (font == this.font)) {
787             return this.fontMetrics;
788         }
789         FontMetrics fm =
790           FontDesignMetrics.getMetrics(font, getFontRenderContext());
791 
792         if (this.font == font) {
793             this.fontMetrics = fm;
794         }
795         return fm;
796     }
797 
798     
799 
800 
801 
802 
803 
804 
805 
806 
807 
808 
809 
810 
811 
812 
813 
814 
815     public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
816         if (onStroke) {
817             s = stroke.createStrokedShape(s);
818         }
819 
820         s = transformShape(s);
821         if ((constrainX|constrainY) != 0) {
822             rect = new Rectangle(rect);
823             rect.translate(constrainX, constrainY);
824         }
825 
826         return s.intersects(rect);
827     }
828 
829     
830 
831 
832     public ColorModel getDeviceColorModel() {
833         return surfaceData.getColorModel();
834     }
835 
836     
837 
838 
839     public GraphicsConfiguration getDeviceConfiguration() {
840         return surfaceData.getDeviceConfiguration();
841     }
842 
843     
844 
845 
846 
847     public final SurfaceData getSurfaceData() {
848         return surfaceData;
849     }
850 
851     
852 
853 
854 
855 
856 
857 
858 
859 
860 
861     public void setComposite(Composite comp) {
862         if (composite == comp) {
863             return;
864         }
865         int newCompState;
866         CompositeType newCompType;
867         if (comp instanceof AlphaComposite) {
868             AlphaComposite alphacomp = (AlphaComposite) comp;
869             newCompType = CompositeType.forAlphaComposite(alphacomp);
870             if (newCompType == CompositeType.SrcOverNoEa) {
871                 if (paintState == PAINT_OPAQUECOLOR ||
872                     (paintState > PAINT_ALPHACOLOR &&
873                      paint.getTransparency() == Transparency.OPAQUE))
874                 {
875                     newCompState = COMP_ISCOPY;
876                 } else {
877                     newCompState = COMP_ALPHA;
878                 }
879             } else if (newCompType == CompositeType.SrcNoEa ||
880                        newCompType == CompositeType.Src ||
881                        newCompType == CompositeType.Clear)
882             {
883                 newCompState = COMP_ISCOPY;
884             } else if (surfaceData.getTransparency() == Transparency.OPAQUE &&
885                        newCompType == CompositeType.SrcIn)
886             {
887                 newCompState = COMP_ISCOPY;
888             } else {
889                 newCompState = COMP_ALPHA;
890             }
891         } else if (comp instanceof XORComposite) {
892             newCompState = COMP_XOR;
893             newCompType = CompositeType.Xor;
894         } else if (comp == null) {
895             throw new IllegalArgumentException("null Composite");
896         } else {
897             surfaceData.checkCustomComposite();
898             newCompState = COMP_CUSTOM;
899             newCompType = CompositeType.General;
900         }
901         if (compositeState != newCompState ||
902             imageComp != newCompType)
903         {
904             compositeState = newCompState;
905             imageComp = newCompType;
906             invalidatePipe();
907             validFontInfo = false;
908         }
909         composite = comp;
910         if (paintState <= PAINT_ALPHACOLOR) {
911             validateColor();
912         }
913     }
914 
915     
916 
917 
918 
919 
920 
921 
922 
923     public void setPaint(Paint paint) {
924         if (paint instanceof Color) {
925             setColor((Color) paint);
926             return;
927         }
928         if (paint == null || this.paint == paint) {
929             return;
930         }
931         this.paint = paint;
932         if (imageComp == CompositeType.SrcOverNoEa) {
933             
934             if (paint.getTransparency() == Transparency.OPAQUE) {
935                 if (compositeState != COMP_ISCOPY) {
936                     compositeState = COMP_ISCOPY;
937                 }
938             } else {
939                 if (compositeState == COMP_ISCOPY) {
940                     compositeState = COMP_ALPHA;
941                 }
942             }
943         }
944         Class paintClass = paint.getClass();
945         if (paintClass == GradientPaint.class) {
946             paintState = PAINT_GRADIENT;
947         } else if (paintClass == LinearGradientPaint.class) {
948             paintState = PAINT_LIN_GRADIENT;
949         } else if (paintClass == RadialGradientPaint.class) {
950             paintState = PAINT_RAD_GRADIENT;
951         } else if (paintClass == TexturePaint.class) {
952             paintState = PAINT_TEXTURE;
953         } else {
954             paintState = PAINT_CUSTOM;
955         }
956         validFontInfo = false;
957         invalidatePipe();
958     }
959 
960     static final int NON_UNIFORM_SCALE_MASK =
961         (AffineTransform.TYPE_GENERAL_TRANSFORM |
962          AffineTransform.TYPE_GENERAL_SCALE);
963     public static final double MinPenSizeAA =
964         sun.java2d.pipe.RenderingEngine.getInstance().getMinimumAAPenSize();
965     public static final double MinPenSizeAASquared =
966         (MinPenSizeAA * MinPenSizeAA);
967     
968     
969     
970     
971     
972     public static final double MinPenSizeSquared = 1.000000001;
973 
974     private void validateBasicStroke(BasicStroke bs) {
975         boolean aa = (antialiasHint == SunHints.INTVAL_ANTIALIAS_ON);
976         if (transformState < TRANSFORM_TRANSLATESCALE) {
977             if (aa) {
978                 if (bs.getLineWidth() <= MinPenSizeAA) {
979                     if (bs.getDashArray() == null) {
980                         strokeState = STROKE_THIN;
981                     } else {
982                         strokeState = STROKE_THINDASHED;
983                     }
984                 } else {
985                     strokeState = STROKE_WIDE;
986                 }
987             } else {
988                 if (bs == defaultStroke) {
989                     strokeState = STROKE_THIN;
990                 } else if (bs.getLineWidth() <= 1.0f) {
991                     if (bs.getDashArray() == null) {
992                         strokeState = STROKE_THIN;
993                     } else {
994                         strokeState = STROKE_THINDASHED;
995                     }
996                 } else {
997                     strokeState = STROKE_WIDE;
998                 }
999             }
1000         } else {
1001             double widthsquared;
1002             if ((transform.getType() & NON_UNIFORM_SCALE_MASK) == 0) {
1003                 
1004                 widthsquared = Math.abs(transform.getDeterminant());
1005             } else {
1006                 
1007                 double A = transform.getScaleX();       
1008                 double C = transform.getShearX();       
1009                 double B = transform.getShearY();       
1010                 double D = transform.getScaleY();       
1011 
1012                 
1013 
1014 
1015 
1016 
1017 
1018 
1019 
1020 
1021 
1022 
1023 
1024 
1025 
1026                 double EA = A*A + B*B;          
1027                 double EB = 2*(A*C + B*D);      
1028                 double EC = C*C + D*D;          
1029 
1030                 
1031 
1032 
1033 
1034 
1035 
1036 
1037 
1038 
1039 
1040 
1041 
1042 
1043 
1044 
1045 
1046 
1047 
1048 
1049 
1050 
1051 
1052                 double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));
1053 
1054                 
1055                 widthsquared = ((EA + EC + hypot)/2.0);
1056             }
1057             if (bs != defaultStroke) {
1058                 widthsquared *= bs.getLineWidth() * bs.getLineWidth();
1059             }
1060             if (widthsquared <=
1061                 (aa ? MinPenSizeAASquared : MinPenSizeSquared))
1062             {
1063                 if (bs.getDashArray() == null) {
1064                     strokeState = STROKE_THIN;
1065                 } else {
1066                     strokeState = STROKE_THINDASHED;
1067                 }
1068             } else {
1069                 strokeState = STROKE_WIDE;
1070             }
1071         }
1072     }
1073 
1074     
1075 
1076 
1077 
1078 
1079 
1080     public void setStroke(Stroke s) {
1081         if (s == null) {
1082             throw new IllegalArgumentException("null Stroke");
1083         }
1084         int saveStrokeState = strokeState;
1085         stroke = s;
1086         if (s instanceof BasicStroke) {
1087             validateBasicStroke((BasicStroke) s);
1088         } else {
1089             strokeState = STROKE_CUSTOM;
1090         }
1091         if (strokeState != saveStrokeState) {
1092             invalidatePipe();
1093         }
1094     }
1095 
1096     
1097 
1098 
1099 
1100 
1101 
1102 
1103 
1104 
1105 
1106 
1107     public void setRenderingHint(Key hintKey, Object hintValue) {
1108         
1109         
1110         
1111         
1112         
1113         if (!hintKey.isCompatibleValue(hintValue)) {
1114             throw new IllegalArgumentException
1115                 (hintValue+" is not compatible with "+hintKey);
1116         }
1117         if (hintKey instanceof SunHints.Key) {
1118             boolean stateChanged;
1119             boolean textStateChanged = false;
1120             boolean recognized = true;
1121             SunHints.Key sunKey = (SunHints.Key) hintKey;
1122             int newHint;
1123             if (sunKey == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST) {
1124                 newHint = ((Integer)hintValue).intValue();
1125             } else {
1126                 newHint = ((SunHints.Value) hintValue).getIndex();
1127             }
1128             switch (sunKey.getIndex()) {
1129             case SunHints.INTKEY_RENDERING:
1130                 stateChanged = (renderHint != newHint);
1131                 if (stateChanged) {
1132                     renderHint = newHint;
1133                     if (interpolationHint == -1) {
1134                         interpolationType =
1135                             (newHint == SunHints.INTVAL_RENDER_QUALITY
1136                              ? AffineTransformOp.TYPE_BILINEAR
1137                              : AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
1138                     }
1139                 }
1140                 break;
1141             case SunHints.INTKEY_ANTIALIASING:
1142                 stateChanged = (antialiasHint != newHint);
1143                 antialiasHint = newHint;
1144                 if (stateChanged) {
1145                     textStateChanged =
1146                         (textAntialiasHint ==
1147                          SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT);
1148                     if (strokeState != STROKE_CUSTOM) {
1149                         validateBasicStroke((BasicStroke) stroke);
1150                     }
1151                 }
1152                 break;
1153             case SunHints.INTKEY_TEXT_ANTIALIASING:
1154                 stateChanged = (textAntialiasHint != newHint);
1155                 textStateChanged = stateChanged;
1156                 textAntialiasHint = newHint;
1157                 break;
1158             case SunHints.INTKEY_FRACTIONALMETRICS:
1159                 stateChanged = (fractionalMetricsHint != newHint);
1160                 textStateChanged = stateChanged;
1161                 fractionalMetricsHint = newHint;
1162                 break;
1163             case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1164                 stateChanged = false;
1165                 
1166                 lcdTextContrast = newHint;
1167                 break;
1168             case SunHints.INTKEY_INTERPOLATION:
1169                 interpolationHint = newHint;
1170                 switch (newHint) {
1171                 case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1172                     newHint = AffineTransformOp.TYPE_BICUBIC;
1173                     break;
1174                 case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1175                     newHint = AffineTransformOp.TYPE_BILINEAR;
1176                     break;
1177                 default:
1178                 case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1179                     newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1180                     break;
1181                 }
1182                 stateChanged = (interpolationType != newHint);
1183                 interpolationType = newHint;
1184                 break;
1185             case SunHints.INTKEY_STROKE_CONTROL:
1186                 stateChanged = (strokeHint != newHint);
1187                 strokeHint = newHint;
1188                 break;
1189             default:
1190                 recognized = false;
1191                 stateChanged = false;
1192                 break;
1193             }
1194             if (recognized) {
1195                 if (stateChanged) {
1196                     invalidatePipe();
1197                     if (textStateChanged) {
1198                         fontMetrics = null;
1199                         this.cachedFRC = null;
1200                         validFontInfo = false;
1201                         this.glyphVectorFontInfo = null;
1202                     }
1203                 }
1204                 if (hints != null) {
1205                     hints.put(hintKey, hintValue);
1206                 }
1207                 return;
1208             }
1209         }
1210         
1211         if (hints == null) {
1212             hints = makeHints(null);
1213         }
1214         hints.put(hintKey, hintValue);
1215     }
1216 
1217 
1218     
1219 
1220 
1221 
1222 
1223 
1224 
1225 
1226     public Object getRenderingHint(Key hintKey) {
1227         if (hints != null) {
1228             return hints.get(hintKey);
1229         }
1230         if (!(hintKey instanceof SunHints.Key)) {
1231             return null;
1232         }
1233         int keyindex = ((SunHints.Key)hintKey).getIndex();
1234         switch (keyindex) {
1235         case SunHints.INTKEY_RENDERING:
1236             return SunHints.Value.get(SunHints.INTKEY_RENDERING,
1237                                       renderHint);
1238         case SunHints.INTKEY_ANTIALIASING:
1239             return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1240                                       antialiasHint);
1241         case SunHints.INTKEY_TEXT_ANTIALIASING:
1242             return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1243                                       textAntialiasHint);
1244         case SunHints.INTKEY_FRACTIONALMETRICS:
1245             return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1246                                       fractionalMetricsHint);
1247         case SunHints.INTKEY_AATEXT_LCD_CONTRAST:
1248             return new Integer(lcdTextContrast);
1249         case SunHints.INTKEY_INTERPOLATION:
1250             switch (interpolationHint) {
1251             case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1252                 return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1253             case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1254                 return SunHints.VALUE_INTERPOLATION_BILINEAR;
1255             case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1256                 return SunHints.VALUE_INTERPOLATION_BICUBIC;
1257             }
1258             return null;
1259         case SunHints.INTKEY_STROKE_CONTROL:
1260             return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1261                                       strokeHint);
1262         }
1263         return null;
1264     }
1265 
1266     
1267 
1268 
1269 
1270 
1271 
1272 
1273     public void setRenderingHints(Map<?,?> hints) {
1274         this.hints = null;
1275         renderHint = SunHints.INTVAL_RENDER_DEFAULT;
1276         antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;
1277         textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;
1278         fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;
1279         lcdTextContrast = lcdTextContrastDefaultValue;
1280         interpolationHint = -1;
1281         interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
1282         boolean customHintPresent = false;
1283         Iterator iter = hints.keySet().iterator();
1284         while (iter.hasNext()) {
1285             Object key = iter.next();
1286             if (key == SunHints.KEY_RENDERING ||
1287                 key == SunHints.KEY_ANTIALIASING ||
1288                 key == SunHints.KEY_TEXT_ANTIALIASING ||
1289                 key == SunHints.KEY_FRACTIONALMETRICS ||
1290                 key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||
1291                 key == SunHints.KEY_STROKE_CONTROL ||
1292                 key == SunHints.KEY_INTERPOLATION)
1293             {
1294                 setRenderingHint((Key) key, hints.get(key));
1295             } else {
1296                 customHintPresent = true;
1297             }
1298         }
1299         if (customHintPresent) {
1300             this.hints = makeHints(hints);
1301         }
1302         invalidatePipe();
1303     }
1304 
1305     
1306 
1307 
1308 
1309 
1310 
1311 
1312     public void addRenderingHints(Map<?,?> hints) {
1313         boolean customHintPresent = false;
1314         Iterator iter = hints.keySet().iterator();
1315         while (iter.hasNext()) {
1316             Object key = iter.next();
1317             if (key == SunHints.KEY_RENDERING ||
1318                 key == SunHints.KEY_ANTIALIASING ||
1319                 key == SunHints.KEY_TEXT_ANTIALIASING ||
1320                 key == SunHints.KEY_FRACTIONALMETRICS ||
1321                 key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||
1322                 key == SunHints.KEY_STROKE_CONTROL ||
1323                 key == SunHints.KEY_INTERPOLATION)
1324             {
1325                 setRenderingHint((Key) key, hints.get(key));
1326             } else {
1327                 customHintPresent = true;
1328             }
1329         }
1330         if (customHintPresent) {
1331             if (this.hints == null) {
1332                 this.hints = makeHints(hints);
1333             } else {
1334                 this.hints.putAll(hints);
1335             }
1336         }
1337     }
1338 
1339     
1340 
1341 
1342 
1343 
1344 
1345     public RenderingHints getRenderingHints() {
1346         if (hints == null) {
1347             return makeHints(null);
1348         } else {
1349             return (RenderingHints) hints.clone();
1350         }
1351     }
1352 
1353     RenderingHints makeHints(Map hints) {
1354         RenderingHints model = new RenderingHints(hints);
1355         model.put(SunHints.KEY_RENDERING,
1356                   SunHints.Value.get(SunHints.INTKEY_RENDERING,
1357                                      renderHint));
1358         model.put(SunHints.KEY_ANTIALIASING,
1359                   SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,
1360                                      antialiasHint));
1361         model.put(SunHints.KEY_TEXT_ANTIALIASING,
1362                   SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,
1363                                      textAntialiasHint));
1364         model.put(SunHints.KEY_FRACTIONALMETRICS,
1365                   SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
1366                                      fractionalMetricsHint));
1367         model.put(SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST,
1368                   Integer.valueOf(lcdTextContrast));
1369         Object value;
1370         switch (interpolationHint) {
1371         case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:
1372             value = SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
1373             break;
1374         case SunHints.INTVAL_INTERPOLATION_BILINEAR:
1375             value = SunHints.VALUE_INTERPOLATION_BILINEAR;
1376             break;
1377         case SunHints.INTVAL_INTERPOLATION_BICUBIC:
1378             value = SunHints.VALUE_INTERPOLATION_BICUBIC;
1379             break;
1380         default:
1381             value = null;
1382             break;
1383         }
1384         if (value != null) {
1385             model.put(SunHints.KEY_INTERPOLATION, value);
1386         }
1387         model.put(SunHints.KEY_STROKE_CONTROL,
1388                   SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,
1389                                      strokeHint));
1390         return model;
1391     }
1392 
1393     
1394 
1395 
1396 
1397 
1398 
1399 
1400 
1401 
1402 
1403 
1404     public void translate(double tx, double ty) {
1405         transform.translate(tx, ty);
1406         invalidateTransform();
1407     }
1408 
1409     
1410 
1411 
1412 
1413 
1414 
1415 
1416 
1417 
1418 
1419 
1420 
1421 
1422 
1423     public void rotate(double theta) {
1424         transform.rotate(theta);
1425         invalidateTransform();
1426     }
1427 
1428     
1429 
1430 
1431 
1432 
1433 
1434 
1435 
1436 
1437 
1438 
1439 
1440 
1441 
1442 
1443     public void rotate(double theta, double x, double y) {
1444         transform.rotate(theta, x, y);
1445         invalidateTransform();
1446     }
1447 
1448     
1449 
1450 
1451 
1452 
1453 
1454 
1455 
1456 
1457 
1458 
1459     public void scale(double sx, double sy) {
1460         transform.scale(sx, sy);
1461         invalidateTransform();
1462     }
1463 
1464     
1465 
1466 
1467 
1468 
1469 
1470 
1471 
1472 
1473 
1474 
1475 
1476 
1477 
1478 
1479     public void shear(double shx, double shy) {
1480         transform.shear(shx, shy);
1481         invalidateTransform();
1482     }
1483 
1484     
1485 
1486 
1487 
1488 
1489 
1490 
1491 
1492 
1493 
1494 
1495 
1496 
1497 
1498 
1499 
1500 
1501     public void transform(AffineTransform xform) {
1502         this.transform.concatenate(xform);
1503         invalidateTransform();
1504     }
1505 
1506     
1507 
1508 
1509     public void translate(int x, int y) {
1510         transform.translate(x, y);
1511         if (transformState <= TRANSFORM_INT_TRANSLATE) {
1512             transX += x;
1513             transY += y;
1514             transformState = (((transX | transY) == 0) ?
1515                               TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);
1516         } else {
1517             invalidateTransform();
1518         }
1519     }
1520 
1521     
1522 
1523 
1524 
1525 
1526 
1527 
1528     public void setTransform(AffineTransform Tx) {
1529         if ((constrainX|constrainY) == 0) {
1530             transform.setTransform(Tx);
1531         } else {
1532             transform.setToTranslation(constrainX, constrainY);
1533             transform.concatenate(Tx);
1534         }
1535         invalidateTransform();
1536     }
1537 
1538     protected void invalidateTransform() {
1539         int type = transform.getType();
1540         int origTransformState = transformState;
1541         if (type == AffineTransform.TYPE_IDENTITY) {
1542             transformState = TRANSFORM_ISIDENT;
1543             transX = transY = 0;
1544         } else if (type == AffineTransform.TYPE_TRANSLATION) {
1545             double dtx = transform.getTranslateX();
1546             double dty = transform.getTranslateY();
1547             transX = (int) Math.floor(dtx + 0.5);
1548             transY = (int) Math.floor(dty + 0.5);
1549             if (dtx == transX && dty == transY) {
1550                 transformState = TRANSFORM_INT_TRANSLATE;
1551             } else {
1552                 transformState = TRANSFORM_ANY_TRANSLATE;
1553             }
1554         } else if ((type & (AffineTransform.TYPE_FLIP |
1555                             AffineTransform.TYPE_MASK_ROTATION |
1556                             AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0)
1557         {
1558             transformState = TRANSFORM_TRANSLATESCALE;
1559             transX = transY = 0;
1560         } else {
1561             transformState = TRANSFORM_GENERIC;
1562             transX = transY = 0;
1563         }
1564 
1565         if (transformState >= TRANSFORM_TRANSLATESCALE ||
1566             origTransformState >= TRANSFORM_TRANSLATESCALE)
1567         {
1568             
1569 
1570 
1571             cachedFRC = null;
1572             this.validFontInfo = false;
1573             this.fontMetrics = null;
1574             this.glyphVectorFontInfo = null;
1575 
1576             if (transformState != origTransformState) {
1577                 invalidatePipe();
1578             }
1579         }
1580         if (strokeState != STROKE_CUSTOM) {
1581             validateBasicStroke((BasicStroke) stroke);
1582         }
1583     }
1584 
1585     
1586 
1587 
1588 
1589 
1590     public AffineTransform getTransform() {
1591         if ((constrainX|constrainY) == 0) {
1592             return new AffineTransform(transform);
1593         }
1594         AffineTransform tx =
1595             AffineTransform.getTranslateInstance(-constrainX, -constrainY);
1596         tx.concatenate(transform);
1597         return tx;
1598     }
1599 
1600     
1601 
1602 
1603 
1604     public AffineTransform cloneTransform() {
1605         return new AffineTransform(transform);
1606     }
1607 
1608     
1609 
1610 
1611 
1612 
1613     public Paint getPaint() {
1614         return paint;
1615     }
1616 
1617     
1618 
1619 
1620 
1621     public Composite getComposite() {
1622         return composite;
1623     }
1624 
1625     public Color getColor() {
1626         return foregroundColor;
1627     }
1628 
1629     
1630 
1631 
1632 
1633 
1634 
1635 
1636 
1637 
1638 
1639 
1640 
1641 
1642 
1643 
1644 
1645 
1646 
1647 
1648 
1649     final void validateColor() {
1650         int eargb;
1651         if (imageComp == CompositeType.Clear) {
1652             eargb = 0;
1653         } else {
1654             eargb = foregroundColor.getRGB();
1655             if (compositeState <= COMP_ALPHA &&
1656                 imageComp != CompositeType.SrcNoEa &&
1657                 imageComp != CompositeType.SrcOverNoEa)
1658             {
1659                 AlphaComposite alphacomp = (AlphaComposite) composite;
1660                 int a = Math.round(alphacomp.getAlpha() * (eargb >>> 24));
1661                 eargb = (eargb & 0x00ffffff) | (a << 24);
1662             }
1663         }
1664         this.eargb = eargb;
1665         this.pixel = surfaceData.pixelFor(eargb);
1666     }
1667 
1668     public void setColor(Color color) {
1669         if (color == null || color == paint) {
1670             return;
1671         }
1672         this.paint = foregroundColor = color;
1673         validateColor();
1674         if ((eargb >> 24) == -1) {
1675             if (paintState == PAINT_OPAQUECOLOR) {
1676                 return;
1677             }
1678             paintState = PAINT_OPAQUECOLOR;
1679             if (imageComp == CompositeType.SrcOverNoEa) {
1680                 
1681                 compositeState = COMP_ISCOPY;
1682             }
1683         } else {
1684             if (paintState == PAINT_ALPHACOLOR) {
1685                 return;
1686             }
1687             paintState = PAINT_ALPHACOLOR;
1688             if (imageComp == CompositeType.SrcOverNoEa) {
1689                 
1690                 compositeState = COMP_ALPHA;
1691             }
1692         }
1693         validFontInfo = false;
1694         invalidatePipe();
1695     }
1696 
1697     
1698 
1699 
1700 
1701 
1702 
1703 
1704 
1705 
1706 
1707 
1708 
1709     public void setBackground(Color color) {
1710         backgroundColor = color;
1711     }
1712 
1713     
1714 
1715 
1716 
1717     public Color getBackground() {
1718         return backgroundColor;
1719     }
1720 
1721     
1722 
1723 
1724 
1725     public Stroke getStroke() {
1726         return stroke;
1727     }
1728 
1729     public Rectangle getClipBounds() {
1730         Rectangle r;
1731         if (clipState == CLIP_DEVICE) {
1732             r = null;
1733         } else if (transformState <= TRANSFORM_INT_TRANSLATE) {
1734             if (usrClip instanceof Rectangle) {
1735                 r = new Rectangle((Rectangle) usrClip);
1736             } else {
1737                 r = usrClip.getBounds();
1738             }
1739             r.translate(-transX, -transY);
1740         } else {
1741             r = getClip().getBounds();
1742         }
1743         return r;
1744     }
1745 
1746     public Rectangle getClipBounds(Rectangle r) {
1747         if (clipState != CLIP_DEVICE) {
1748             if (transformState <= TRANSFORM_INT_TRANSLATE) {
1749                 if (usrClip instanceof Rectangle) {
1750                     r.setBounds((Rectangle) usrClip);
1751                 } else {
1752                     r.setBounds(usrClip.getBounds());
1753                 }
1754                 r.translate(-transX, -transY);
1755             } else {
1756                 r.setBounds(getClip().getBounds());
1757             }
1758         } else if (r == null) {
1759             throw new NullPointerException("null rectangle parameter");
1760         }
1761         return r;
1762     }
1763 
1764     public boolean hitClip(int x, int y, int width, int height) {
1765         if (width <= 0 || height <= 0) {
1766             return false;
1767         }
1768         if (transformState > TRANSFORM_INT_TRANSLATE) {
1769             
1770             
1771             
1772             
1773             
1774             
1775             
1776             
1777             
1778             
1779             
1780             
1781             
1782             
1783             
1784             
1785 
1786             double d[] = {
1787                 x, y,
1788                 x+width, y,
1789                 x, y+height,
1790                 x+width, y+height
1791             };
1792             transform.transform(d, 0, d, 0, 4);
1793             x = (int) Math.floor(Math.min(Math.min(d[0], d[2]),
1794                                           Math.min(d[4], d[6])));
1795             y = (int) Math.floor(Math.min(Math.min(d[1], d[3]),
1796                                           Math.min(d[5], d[7])));
1797             width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]),
1798                                              Math.max(d[4], d[6])));
1799             height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]),
1800                                               Math.max(d[5], d[7])));
1801         } else {
1802             x += transX;
1803             y += transY;
1804             width += x;
1805             height += y;
1806         }
1807         if (!getCompClip().intersectsQuickCheckXYXY(x, y, width, height)) {
1808             return false;
1809         }
1810         
1811         
1812         
1813         
1814         
1815         return true;
1816     }
1817 
1818     protected void validateCompClip() {
1819         int origClipState = clipState;
1820         if (usrClip == null) {
1821             clipState = CLIP_DEVICE;
1822             clipRegion = devClip;
1823         } else if (usrClip instanceof Rectangle2D) {
1824             clipState = CLIP_RECTANGULAR;
1825             if (usrClip instanceof Rectangle) {
1826                 clipRegion = devClip.getIntersection((Rectangle)usrClip);
1827             } else {
1828                 clipRegion = devClip.getIntersection(usrClip.getBounds());
1829             }
1830         } else {
1831             PathIterator cpi = usrClip.getPathIterator(null);
1832             int box[] = new int[4];
1833             ShapeSpanIterator sr = LoopPipe.getFillSSI(this);
1834             try {
1835                 sr.setOutputArea(devClip);
1836                 sr.appendPath(cpi);
1837                 sr.getPathBox(box);
1838                 Region r = Region.getInstance(box);
1839                 r.appendSpans(sr);
1840                 clipRegion = r;
1841                 clipState =
1842                     r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE;
1843             } finally {
1844                 sr.dispose();
1845             }
1846         }
1847         if (origClipState != clipState &&
1848             (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE))
1849         {
1850             validFontInfo = false;
1851             invalidatePipe();
1852         }
1853     }
1854 
1855     static final int NON_RECTILINEAR_TRANSFORM_MASK =
1856         (AffineTransform.TYPE_GENERAL_TRANSFORM |
1857          AffineTransform.TYPE_GENERAL_ROTATION);
1858 
1859     protected Shape transformShape(Shape s) {
1860         if (s == null) {
1861             return null;
1862         }
1863         if (transformState > TRANSFORM_INT_TRANSLATE) {
1864             return transformShape(transform, s);
1865         } else {
1866             return transformShape(transX, transY, s);
1867         }
1868     }
1869 
1870     public Shape untransformShape(Shape s) {
1871         if (s == null) {
1872             return null;
1873         }
1874         if (transformState > TRANSFORM_INT_TRANSLATE) {
1875             try {
1876                 return transformShape(transform.createInverse(), s);
1877             } catch (NoninvertibleTransformException e) {
1878                 return null;
1879             }
1880         } else {
1881             return transformShape(-transX, -transY, s);
1882         }
1883     }
1884 
1885     protected static Shape transformShape(int tx, int ty, Shape s) {
1886         if (s == null) {
1887             return null;
1888         }
1889 
1890         if (s instanceof Rectangle) {
1891             Rectangle r = s.getBounds();
1892             r.translate(tx, ty);
1893             return r;
1894         }
1895         if (s instanceof Rectangle2D) {
1896             Rectangle2D rect = (Rectangle2D) s;
1897             return new Rectangle2D.Double(rect.getX() + tx,
1898                                           rect.getY() + ty,
1899                                           rect.getWidth(),
1900                                           rect.getHeight());
1901         }
1902 
1903         if (tx == 0 && ty == 0) {
1904             return cloneShape(s);
1905         }
1906 
1907         AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty);
1908         return mat.createTransformedShape(s);
1909     }
1910 
1911     protected static Shape transformShape(AffineTransform tx, Shape clip) {
1912         if (clip == null) {
1913             return null;
1914         }
1915 
1916         if (clip instanceof Rectangle2D &&
1917             (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)
1918         {
1919             Rectangle2D rect = (Rectangle2D) clip;
1920             double matrix[] = new double[4];
1921             matrix[0] = rect.getX();
1922             matrix[1] = rect.getY();
1923             matrix[2] = matrix[0] + rect.getWidth();
1924             matrix[3] = matrix[1] + rect.getHeight();
1925             tx.transform(matrix, 0, matrix, 0, 2);
1926             rect = new Rectangle2D.Float();
1927             rect.setFrameFromDiagonal(matrix[0], matrix[1],
1928                                       matrix[2], matrix[3]);
1929             return rect;
1930         }
1931 
1932         if (tx.isIdentity()) {
1933             return cloneShape(clip);
1934         }
1935 
1936         return tx.createTransformedShape(clip);
1937     }
1938 
1939     public void clipRect(int x, int y, int w, int h) {
1940         clip(new Rectangle(x, y, w, h));
1941     }
1942 
1943     public void setClip(int x, int y, int w, int h) {
1944         setClip(new Rectangle(x, y, w, h));
1945     }
1946 
1947     public Shape getClip() {
1948         return untransformShape(usrClip);
1949     }
1950 
1951     public void setClip(Shape sh) {
1952         usrClip = transformShape(sh);
1953         validateCompClip();
1954     }
1955 
1956     
1957 
1958 
1959 
1960 
1961 
1962 
1963 
1964     public void clip(Shape s) {
1965         s = transformShape(s);
1966         if (usrClip != null) {
1967             s = intersectShapes(usrClip, s, true, true);
1968         }
1969         usrClip = s;
1970         validateCompClip();
1971     }
1972 
1973     public void setPaintMode() {
1974         setComposite(AlphaComposite.SrcOver);
1975     }
1976 
1977     public void setXORMode(Color c) {
1978         if (c == null) {
1979             throw new IllegalArgumentException("null XORColor");
1980         }
1981         setComposite(new XORComposite(c, surfaceData));
1982     }
1983 
1984     Blit lastCAblit;
1985     Composite lastCAcomp;
1986 
1987     public void copyArea(int x, int y, int w, int h, int dx, int dy) {
1988         try {
1989             doCopyArea(x, y, w, h, dx, dy);
1990         } catch (InvalidPipeException e) {
1991             revalidateAll();
1992             try {
1993                 doCopyArea(x, y, w, h, dx, dy);
1994             } catch (InvalidPipeException e2) {
1995                 
1996                 
1997                 
1998             }
1999         } finally {
2000             surfaceData.markDirty();
2001         }
2002     }
2003 
2004     private void doCopyArea(int x, int y, int w, int h, int dx, int dy) {
2005         if (w <= 0 || h <= 0) {
2006             return;
2007         }
2008         SurfaceData theData = surfaceData;
2009         if (theData.copyArea(this, x, y, w, h, dx, dy)) {
2010             return;
2011         }
2012         if (transformState >= TRANSFORM_TRANSLATESCALE) {
2013             throw new InternalError("transformed copyArea not implemented yet");
2014         }
2015         
2016         
2017 
2018         Region clip = getCompClip();
2019 
2020         Composite comp = composite;
2021         if (lastCAcomp != comp) {
2022             SurfaceType dsttype = theData.getSurfaceType();
2023             CompositeType comptype = imageComp;
2024             if (CompositeType.SrcOverNoEa.equals(comptype) &&
2025                 theData.getTransparency() == Transparency.OPAQUE)
2026             {
2027                 comptype = CompositeType.SrcNoEa;
2028             }
2029             lastCAblit = Blit.locate(dsttype, comptype, dsttype);
2030             lastCAcomp = comp;
2031         }
2032 
2033         x += transX;
2034         y += transY;
2035 
2036         Blit ob = lastCAblit;
2037         if (dy == 0 && dx > 0 && dx < w) {
2038             while (w > 0) {
2039                 int partW = Math.min(w, dx);
2040                 w -= partW;
2041                 int sx = x + w;
2042                 ob.Blit(theData, theData, comp, clip,
2043                         sx, y, sx+dx, y+dy, partW, h);
2044             }
2045             return;
2046         }
2047         if (dy > 0 && dy < h && dx > -w && dx < w) {
2048             while (h > 0) {
2049                 int partH = Math.min(h, dy);
2050                 h -= partH;
2051                 int sy = y + h;
2052                 ob.Blit(theData, theData, comp, clip,
2053                         x, sy, x+dx, sy+dy, w, partH);
2054             }
2055             return;
2056         }
2057         ob.Blit(theData, theData, comp, clip, x, y, x+dx, y+dy, w, h);
2058     }
2059 
2060     
2061 
2062 
2063 
2064 
2065 
2066 
2067 
2068 
2069 
2070 
2071 
2072 
2073 
2074 
2075 
2076 
2077 
2078 
2079 
2080 
2081 
2082 
2083 
2084 
2085 
2086 
2087 
2088 
2089 
2090 
2091 
2092 
2093 
2094 
2095 
2096 
2097 
2098 
2099 
2100 
2101 
2102 
2103 
2104 
2105 
2106 
2107 
2108 
2109 
2110 
2111 
2112 
2113 
2114 
2115 
2116 
2117 
2118 
2119     public void drawLine(int x1, int y1, int x2, int y2) {
2120         try {
2121             drawpipe.drawLine(this, x1, y1, x2, y2);
2122         } catch (InvalidPipeException e) {
2123             revalidateAll();
2124             try {
2125                 drawpipe.drawLine(this, x1, y1, x2, y2);
2126             } catch (InvalidPipeException e2) {
2127                 
2128                 
2129                 
2130             }
2131         } finally {
2132             surfaceData.markDirty();
2133         }
2134     }
2135 
2136     public void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH) {
2137         try {
2138             drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH);
2139         } catch (InvalidPipeException e) {
2140             revalidateAll();
2141             try {
2142                 drawpipe.drawRoundRect(this, x, y, w, h, arcW, arcH);
2143             } catch (InvalidPipeException e2) {
2144                 
2145                 
2146                 
2147             }
2148         } finally {
2149             surfaceData.markDirty();
2150         }
2151     }
2152 
2153     public void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH) {
2154         try {
2155             fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH);
2156         } catch (InvalidPipeException e) {
2157             revalidateAll();
2158             try {
2159                 fillpipe.fillRoundRect(this, x, y, w, h, arcW, arcH);
2160             } catch (InvalidPipeException e2) {
2161                 
2162                 
2163                 
2164             }
2165         } finally {
2166             surfaceData.markDirty();
2167         }
2168     }
2169 
2170     public void drawOval(int x, int y, int w, int h) {
2171         try {
2172             drawpipe.drawOval(this, x, y, w, h);
2173         } catch (InvalidPipeException e) {
2174             revalidateAll();
2175             try {
2176                 drawpipe.drawOval(this, x, y, w, h);
2177             } catch (InvalidPipeException e2) {
2178                 
2179                 
2180                 
2181             }
2182         } finally {
2183             surfaceData.markDirty();
2184         }
2185     }
2186 
2187     public void fillOval(int x, int y, int w, int h) {
2188         try {
2189             fillpipe.fillOval(this, x, y, w, h);
2190         } catch (InvalidPipeException e) {
2191             revalidateAll();
2192             try {
2193                 fillpipe.fillOval(this, x, y, w, h);
2194             } catch (InvalidPipeException e2) {
2195                 
2196                 
2197                 
2198             }
2199         } finally {
2200             surfaceData.markDirty();
2201         }
2202     }
2203 
2204     public void drawArc(int x, int y, int w, int h,
2205                         int startAngl, int arcAngl) {
2206         try {
2207             drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl);
2208         } catch (InvalidPipeException e) {
2209             revalidateAll();
2210             try {
2211                 drawpipe.drawArc(this, x, y, w, h, startAngl, arcAngl);
2212             } catch (InvalidPipeException e2) {
2213                 
2214                 
2215                 
2216             }
2217         } finally {
2218             surfaceData.markDirty();
2219         }
2220     }
2221 
2222     public void fillArc(int x, int y, int w, int h,
2223                         int startAngl, int arcAngl) {
2224         try {
2225             fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2226         } catch (InvalidPipeException e) {
2227             revalidateAll();
2228             try {
2229                 fillpipe.fillArc(this, x, y, w, h, startAngl, arcAngl);
2230             } catch (InvalidPipeException e2) {
2231                 
2232                 
2233                 
2234             }
2235         } finally {
2236             surfaceData.markDirty();
2237         }
2238     }
2239 
2240     public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
2241         try {
2242             drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2243         } catch (InvalidPipeException e) {
2244             revalidateAll();
2245             try {
2246                 drawpipe.drawPolyline(this, xPoints, yPoints, nPoints);
2247             } catch (InvalidPipeException e2) {
2248                 
2249                 
2250                 
2251             }
2252         } finally {
2253             surfaceData.markDirty();
2254         }
2255     }
2256 
2257     public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
2258         try {
2259             drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2260         } catch (InvalidPipeException e) {
2261             revalidateAll();
2262             try {
2263                 drawpipe.drawPolygon(this, xPoints, yPoints, nPoints);
2264             } catch (InvalidPipeException e2) {
2265                 
2266                 
2267                 
2268             }
2269         } finally {
2270             surfaceData.markDirty();
2271         }
2272     }
2273 
2274     public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
2275         try {
2276             fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2277         } catch (InvalidPipeException e) {
2278             revalidateAll();
2279             try {
2280                 fillpipe.fillPolygon(this, xPoints, yPoints, nPoints);
2281             } catch (InvalidPipeException e2) {
2282                 
2283                 
2284                 
2285             }
2286         } finally {
2287             surfaceData.markDirty();
2288         }
2289     }
2290 
2291     public void drawRect (int x, int y, int w, int h) {
2292         try {
2293             drawpipe.drawRect(this, x, y, w, h);
2294         } catch (InvalidPipeException e) {
2295             revalidateAll();
2296             try {
2297                 drawpipe.drawRect(this, x, y, w, h);
2298             } catch (InvalidPipeException e2) {
2299                 
2300                 
2301                 
2302             }
2303         } finally {
2304             surfaceData.markDirty();
2305         }
2306     }
2307 
2308     public void fillRect (int x, int y, int w, int h) {
2309         try {
2310             fillpipe.fillRect(this, x, y, w, h);
2311         } catch (InvalidPipeException e) {
2312             revalidateAll();
2313             try {
2314                 fillpipe.fillRect(this, x, y, w, h);
2315             } catch (InvalidPipeException e2) {
2316                 
2317                 
2318                 
2319             }
2320         } finally {
2321             surfaceData.markDirty();
2322         }
2323     }
2324 
2325     private void revalidateAll() {
2326         try {
2327             
2328             
2329             
2330             
2331             
2332             surfaceData = surfaceData.getReplacement();
2333             if (surfaceData == null) {
2334                 surfaceData = NullSurfaceData.theInstance;
2335             }
2336 
2337             
2338             setDevClip(surfaceData.getBounds());
2339 
2340             if (paintState <= PAINT_ALPHACOLOR) {
2341                 validateColor();
2342             }
2343             if (composite instanceof XORComposite) {
2344                 Color c = ((XORComposite) composite).getXorColor();
2345                 setComposite(new XORComposite(c, surfaceData));
2346             }
2347             validatePipe();
2348         } finally {
2349             
2350             
2351         }
2352     }
2353 
2354     public void clearRect(int x, int y, int w, int h) {
2355         
2356         
2357         Composite c = composite;
2358         Paint p = paint;
2359         setComposite(AlphaComposite.Src);
2360         setColor(getBackground());
2361         validatePipe();
2362         fillRect(x, y, w, h);
2363         setPaint(p);
2364         setComposite(c);
2365     }
2366 
2367     
2368 
2369 
2370 
2371 
2372 
2373 
2374 
2375 
2376 
2377 
2378 
2379 
2380 
2381     public void draw(Shape s) {
2382         try {
2383             shapepipe.draw(this, s);
2384         } catch (InvalidPipeException e) {
2385             revalidateAll();
2386             try {
2387                 shapepipe.draw(this, s);
2388             } catch (InvalidPipeException e2) {
2389                 
2390                 
2391                 
2392             }
2393         } finally {
2394             surfaceData.markDirty();
2395         }
2396     }
2397 
2398 
2399     
2400 
2401 
2402 
2403 
2404 
2405 
2406 
2407 
2408 
2409 
2410 
2411     public void fill(Shape s) {
2412         try {
2413             shapepipe.fill(this, s);
2414         } catch (InvalidPipeException e) {
2415             revalidateAll();
2416             try {
2417                 shapepipe.fill(this, s);
2418             } catch (InvalidPipeException e2) {
2419                 
2420                 
2421                 
2422             }
2423         } finally {
2424             surfaceData.markDirty();
2425         }
2426     }
2427 
2428     
2429 
2430 
2431 
2432     private static boolean isIntegerTranslation(AffineTransform xform) {
2433         if (xform.isIdentity()) {
2434             return true;
2435         }
2436         if (xform.getType() == AffineTransform.TYPE_TRANSLATION) {
2437             double tx = xform.getTranslateX();
2438             double ty = xform.getTranslateY();
2439             return (tx == (int)tx && ty == (int)ty);
2440         }
2441         return false;
2442     }
2443 
2444     
2445 
2446 
2447 
2448     private static int getTileIndex(int p, int tileGridOffset, int tileSize) {
2449         p -= tileGridOffset;
2450         if (p < 0) {
2451             p += 1 - tileSize;          
2452         }
2453         return p/tileSize;
2454     }
2455 
2456     
2457 
2458 
2459 
2460 
2461 
2462 
2463     private static Rectangle getImageRegion(RenderedImage img,
2464                                             Region compClip,
2465                                             AffineTransform transform,
2466                                             AffineTransform xform,
2467                                             int padX, int padY) {
2468         Rectangle imageRect =
2469             new Rectangle(img.getMinX(), img.getMinY(),
2470                           img.getWidth(), img.getHeight());
2471 
2472         Rectangle result = null;
2473         try {
2474             double p[] = new double[8];
2475             p[0] = p[2] = compClip.getLoX();
2476             p[4] = p[6] = compClip.getHiX();
2477             p[1] = p[5] = compClip.getLoY();
2478             p[3] = p[7] = compClip.getHiY();
2479 
2480             
2481             transform.inverseTransform(p, 0, p, 0, 4);
2482             xform.inverseTransform(p, 0, p, 0, 4);
2483 
2484             
2485             double x0,x1,y0,y1;
2486             x0 = x1 = p[0];
2487             y0 = y1 = p[1];
2488 
2489             for (int i = 2; i < 8; ) {
2490                 double pt = p[i++];
2491                 if (pt < x0)  {
2492                     x0 = pt;
2493                 } else if (pt > x1) {
2494                     x1 = pt;
2495                 }
2496                 pt = p[i++];
2497                 if (pt < y0)  {
2498                     y0 = pt;
2499                 } else if (pt > y1) {
2500                     y1 = pt;
2501                 }
2502             }
2503 
2504             
2505             
2506             int x = (int)x0 - padX;
2507             int w = (int)(x1 - x0 + 2*padX);
2508             int y = (int)y0 - padY;
2509             int h = (int)(y1 - y0 + 2*padY);
2510 
2511             Rectangle clipRect = new Rectangle(x,y,w,h);
2512             result = clipRect.intersection(imageRect);
2513         } catch (NoninvertibleTransformException nte) {
2514             
2515             result = imageRect;
2516         }
2517 
2518         return result;
2519     }
2520 
2521     
2522 
2523 
2524 
2525 
2526 
2527 
2528 
2529 
2530 
2531 
2532 
2533 
2534 
2535 
2536 
2537 
2538 
2539     public void drawRenderedImage(RenderedImage img,
2540                                   AffineTransform xform) {
2541 
2542         if (img == null) {
2543             return;
2544         }
2545 
2546         
2547         if (img instanceof BufferedImage) {
2548             BufferedImage bufImg = (BufferedImage)img;
2549             drawImage(bufImg,xform,null);
2550             return;
2551         }
2552 
2553         
2554         
2555         
2556         boolean isIntegerTranslate =
2557             (transformState <= TRANSFORM_INT_TRANSLATE) &&
2558             isIntegerTranslation(xform);
2559 
2560         
2561         int pad = isIntegerTranslate ? 0 : 3;
2562 
2563         
2564         
2565         Rectangle region = getImageRegion(img,
2566                                           getCompClip(),
2567                                           transform,
2568                                           xform,
2569                                           pad, pad);
2570         if (region.width <= 0 || region.height <= 0) {
2571             return;
2572         }
2573 
2574         
2575         
2576         
2577         
2578         
2579         if (isIntegerTranslate) {
2580             
2581             
2582             
2583             
2584             
2585 
2586             drawTranslatedRenderedImage(img, region,
2587                                         (int) xform.getTranslateX(),
2588                                         (int) xform.getTranslateY());
2589             return;
2590         }
2591 
2592         
2593         Raster raster = img.getData(region);
2594 
2595         
2596         
2597         
2598         WritableRaster wRaster =
2599               Raster.createWritableRaster(raster.getSampleModel(),
2600                                           raster.getDataBuffer(),
2601                                           null);
2602 
2603         
2604         
2605         
2606         
2607         
2608         int minX = raster.getMinX();
2609         int minY = raster.getMinY();
2610         int width = raster.getWidth();
2611         int height = raster.getHeight();
2612         int px = minX - raster.getSampleModelTranslateX();
2613         int py = minY - raster.getSampleModelTranslateY();
2614         if (px != 0 || py != 0 || width != wRaster.getWidth() ||
2615             height != wRaster.getHeight()) {
2616             wRaster =
2617                 wRaster.createWritableChild(px,
2618                                             py,
2619                                             width,
2620                                             height,
2621                                             0, 0,
2622                                             null);
2623         }
2624 
2625         
2626         
2627         
2628         
2629         AffineTransform transXform = (AffineTransform)xform.clone();
2630         transXform.translate(minX, minY);
2631 
2632         ColorModel cm = img.getColorModel();
2633         BufferedImage bufImg = new BufferedImage(cm,
2634                                                  wRaster,
2635                                                  cm.isAlphaPremultiplied(),
2636                                                  null);
2637         drawImage(bufImg, transXform, null);
2638     }
2639 
2640     
2641 
2642 
2643 
2644 
2645     private boolean clipTo(Rectangle destRect, Rectangle clip) {
2646         int x1 = Math.max(destRect.x, clip.x);
2647         int x2 = Math.min(destRect.x + destRect.width, clip.x + clip.width);
2648         int y1 = Math.max(destRect.y, clip.y);
2649         int y2 = Math.min(destRect.y + destRect.height, clip.y + clip.height);
2650         if (((x2 - x1) < 0) || ((y2 - y1) < 0)) {
2651             destRect.width = -1; 
2652             destRect.height = -1;
2653             return false;
2654         } else {
2655             destRect.x = x1;
2656             destRect.y = y1;
2657             destRect.width = x2 - x1;
2658             destRect.height = y2 - y1;
2659             return true;
2660         }
2661     }
2662 
2663     
2664 
2665 
2666 
2667 
2668     private void drawTranslatedRenderedImage(RenderedImage img,
2669                                              Rectangle region,
2670                                              int i2uTransX,
2671                                              int i2uTransY) {
2672         
2673         int tileGridXOffset = img.getTileGridXOffset();
2674         int tileGridYOffset = img.getTileGridYOffset();
2675         int tileWidth = img.getTileWidth();
2676         int tileHeight = img.getTileHeight();
2677 
2678         
2679         int minTileX =
2680             getTileIndex(region.x, tileGridXOffset, tileWidth);
2681         int minTileY =
2682             getTileIndex(region.y, tileGridYOffset, tileHeight);
2683         int maxTileX =
2684             getTileIndex(region.x + region.width - 1,
2685                          tileGridXOffset, tileWidth);
2686         int maxTileY =
2687             getTileIndex(region.y + region.height - 1,
2688                          tileGridYOffset, tileHeight);
2689 
2690         
2691         ColorModel colorModel = img.getColorModel();
2692 
2693         
2694         Rectangle tileRect = new Rectangle();
2695 
2696         for (int ty = minTileY; ty <= maxTileY; ty++) {
2697             for (int tx = minTileX; tx <= maxTileX; tx++) {
2698                 
2699                 Raster raster = img.getTile(tx, ty);
2700 
2701                 
2702                 tileRect.x = tx*tileWidth + tileGridXOffset;
2703                 tileRect.y = ty*tileHeight + tileGridYOffset;
2704                 tileRect.width = tileWidth;
2705                 tileRect.height = tileHeight;
2706 
2707                 
2708                 
2709                 
2710                 clipTo(tileRect, region);
2711 
2712                 
2713                 WritableRaster wRaster = null;
2714                 if (raster instanceof WritableRaster) {
2715                     wRaster = (WritableRaster)raster;
2716                 } else {
2717                     
2718                     
2719                     wRaster =
2720                         Raster.createWritableRaster(raster.getSampleModel(),
2721                                                     raster.getDataBuffer(),
2722                                                     null);
2723                 }
2724 
2725                 
2726                 
2727                 wRaster = wRaster.createWritableChild(tileRect.x, tileRect.y,
2728                                                       tileRect.width,
2729                                                       tileRect.height,
2730                                                       0, 0,
2731                                                       null);
2732 
2733                 
2734                 BufferedImage bufImg =
2735                     new BufferedImage(colorModel,
2736                                       wRaster,
2737                                       colorModel.isAlphaPremultiplied(),
2738                                       null);
2739                 
2740                 
2741                 
2742                 
2743                 
2744                 
2745                 copyImage(bufImg, tileRect.x + i2uTransX,
2746                           tileRect.y + i2uTransY, 0, 0, tileRect.width,
2747                           tileRect.height, null, null);
2748             }
2749         }
2750     }
2751 
2752     public void drawRenderableImage(RenderableImage img,
2753                                     AffineTransform xform) {
2754 
2755         if (img == null) {
2756             return;
2757         }
2758 
2759         AffineTransform pipeTransform = transform;
2760         AffineTransform concatTransform = new AffineTransform(xform);
2761         concatTransform.concatenate(pipeTransform);
2762         AffineTransform reverseTransform;
2763 
2764         RenderContext rc = new RenderContext(concatTransform);
2765 
2766         try {
2767             reverseTransform = pipeTransform.createInverse();
2768         } catch (NoninvertibleTransformException nte) {
2769             rc = new RenderContext(pipeTransform);
2770             reverseTransform = new AffineTransform();
2771         }
2772 
2773         RenderedImage rendering = img.createRendering(rc);
2774         drawRenderedImage(rendering,reverseTransform);
2775     }
2776 
2777 
2778 
2779     
2780 
2781 
2782     protected Rectangle transformBounds(Rectangle rect,
2783                                         AffineTransform tx) {
2784         if (tx.isIdentity()) {
2785             return rect;
2786         }
2787 
2788         Shape s = transformShape(tx, rect);
2789         return s.getBounds();
2790     }
2791 
2792     
2793     public void drawString(String str, int x, int y) {
2794         if (str == null) {
2795             throw new NullPointerException("String is null");
2796         }
2797 
2798         if (font.hasLayoutAttributes()) {
2799             if (str.length() == 0) {
2800                 return;
2801             }
2802             new TextLayout(str, font, getFontRenderContext()).draw(this, x, y);
2803             return;
2804         }
2805 
2806         try {
2807             textpipe.drawString(this, str, x, y);
2808         } catch (InvalidPipeException e) {
2809             revalidateAll();
2810             try {
2811                 textpipe.drawString(this, str, x, y);
2812             } catch (InvalidPipeException e2) {
2813                 
2814                 
2815                 
2816             }
2817         } finally {
2818             surfaceData.markDirty();
2819         }
2820     }
2821 
2822     public void drawString(String str, float x, float y) {
2823         if (str == null) {
2824             throw new NullPointerException("String is null");
2825         }
2826 
2827         if (font.hasLayoutAttributes()) {
2828             if (str.length() == 0) {
2829                 return;
2830             }
2831             new TextLayout(str, font, getFontRenderContext()).draw(this, x, y);
2832             return;
2833         }
2834 
2835         try {
2836             textpipe.drawString(this, str, x, y);
2837         } catch (InvalidPipeException e) {
2838             revalidateAll();
2839             try {
2840                 textpipe.drawString(this, str, x, y);
2841             } catch (InvalidPipeException e2) {
2842                 
2843                 
2844                 
2845             }
2846         } finally {
2847             surfaceData.markDirty();
2848         }
2849     }
2850 
2851     public void drawString(AttributedCharacterIterator iterator,
2852                            int x, int y) {
2853         if (iterator == null) {
2854             throw new NullPointerException("AttributedCharacterIterator is null");
2855         }
2856         if (iterator.getBeginIndex() == iterator.getEndIndex()) {
2857             return; 
2858         }
2859         TextLayout tl = new TextLayout(iterator, getFontRenderContext());
2860         tl.draw(this, (float) x, (float) y);
2861     }
2862 
2863     public void drawString(AttributedCharacterIterator iterator,
2864                            float x, float y) {
2865         if (iterator == null) {
2866             throw new NullPointerException("AttributedCharacterIterator is null");
2867         }
2868         if (iterator.getBeginIndex() == iterator.getEndIndex()) {
2869             return; 
2870         }
2871         TextLayout tl = new TextLayout(iterator, getFontRenderContext());
2872         tl.draw(this, x, y);
2873     }
2874 
2875     public void drawGlyphVector(GlyphVector gv, float x, float y)
2876     {
2877         if (gv == null) {
2878             throw new NullPointerException("GlyphVector is null");
2879         }
2880 
2881         try {
2882             textpipe.drawGlyphVector(this, gv, x, y);
2883         } catch (InvalidPipeException e) {
2884             revalidateAll();
2885             try {
2886                 textpipe.drawGlyphVector(this, gv, x, y);
2887             } catch (InvalidPipeException e2) {
2888                 
2889                 
2890                 
2891             }
2892         } finally {
2893             surfaceData.markDirty();
2894         }
2895     }
2896 
2897     public void drawChars(char data[], int offset, int length, int x, int y) {
2898 
2899         if (data == null) {
2900             throw new NullPointerException("char data is null");
2901         }
2902         if (offset < 0 || length < 0 || offset + length > data.length) {
2903             throw new ArrayIndexOutOfBoundsException("bad offset/length");
2904         }
2905         if (font.hasLayoutAttributes()) {
2906             if (data.length == 0) {
2907                 return;
2908             }
2909             new TextLayout(new String(data, offset, length),
2910                            font, getFontRenderContext()).draw(this, x, y);
2911             return;
2912         }
2913 
2914         try {
2915             textpipe.drawChars(this, data, offset, length, x, y);
2916         } catch (InvalidPipeException e) {
2917             revalidateAll();
2918             try {
2919                 textpipe.drawChars(this, data, offset, length, x, y);
2920             } catch (InvalidPipeException e2) {
2921                 
2922                 
2923                 
2924             }
2925         } finally {
2926             surfaceData.markDirty();
2927         }
2928     }
2929 
2930     public void drawBytes(byte data[], int offset, int length, int x, int y) {
2931         if (data == null) {
2932             throw new NullPointerException("byte data is null");
2933         }
2934         if (offset < 0 || length < 0 || offset + length > data.length) {
2935             throw new ArrayIndexOutOfBoundsException("bad offset/length");
2936         }
2937         
2938         char chData[] = new char[length];
2939         for (int i = length; i-- > 0; ) {
2940             chData[i] = (char)(data[i+offset] & 0xff);
2941         }
2942         if (font.hasLayoutAttributes()) {
2943             if (data.length == 0) {
2944                 return;
2945             }
2946             new TextLayout(new String(chData),
2947                            font, getFontRenderContext()).draw(this, x, y);
2948             return;
2949         }
2950 
2951         try {
2952             textpipe.drawChars(this, chData, 0, length, x, y);
2953         } catch (InvalidPipeException e) {
2954             revalidateAll();
2955             try {
2956                 textpipe.drawChars(this, chData, 0, length, x, y);
2957             } catch (InvalidPipeException e2) {
2958                 
2959                 
2960                 
2961             }
2962         } finally {
2963             surfaceData.markDirty();
2964         }
2965     }
2966 
2967 
2968     
2969 
2970 
2971 
2972     public boolean drawImage(Image img, int x, int y, int width, int height,
2973                              ImageObserver observer) {
2974         return drawImage(img, x, y, width, height, null, observer);
2975     }
2976 
2977     
2978 
2979 
2980 
2981 
2982 
2983 
2984     public boolean copyImage(Image img, int dx, int dy, int sx, int sy,
2985                              int width, int height, Color bgcolor,
2986                              ImageObserver observer) {
2987         try {
2988             return imagepipe.copyImage(this, img, dx, dy, sx, sy,
2989                                        width, height, bgcolor, observer);
2990         } catch (InvalidPipeException e) {
2991             revalidateAll();
2992             try {
2993                 return imagepipe.copyImage(this, img, dx, dy, sx, sy,
2994                                            width, height, bgcolor, observer);
2995             } catch (InvalidPipeException e2) {
2996                 
2997                 
2998                 
2999                 return false;
3000             }
3001         } finally {
3002             surfaceData.markDirty();
3003         }
3004     }
3005 
3006     
3007 
3008 
3009 
3010     public boolean drawImage(Image img, int x, int y, int width, int height,
3011                              Color bg, ImageObserver observer) {
3012 
3013         if (img == null) {
3014             return true;
3015         }
3016 
3017         if ((width == 0) || (height == 0)) {
3018             return true;
3019         }
3020         if (width == img.getWidth(null) && height == img.getHeight(null)) {
3021             return copyImage(img, x, y, 0, 0, width, height, bg, observer);
3022         }
3023 
3024         try {
3025             return imagepipe.scaleImage(this, img, x, y, width, height,
3026                                         bg, observer);
3027         } catch (InvalidPipeException e) {
3028             revalidateAll();
3029             try {
3030                 return imagepipe.scaleImage(this, img, x, y, width, height,
3031                                             bg, observer);
3032             } catch (InvalidPipeException e2) {
3033                 
3034                 
3035                 
3036                 return false;
3037             }
3038         } finally {
3039             surfaceData.markDirty();
3040         }
3041     }
3042 
3043     
3044 
3045 
3046     public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
3047         return drawImage(img, x, y, null, observer);
3048     }
3049 
3050     
3051 
3052 
3053 
3054     public boolean drawImage(Image img, int x, int y, Color bg,
3055                              ImageObserver observer) {
3056 
3057         if (img == null) {
3058             return true;
3059         }
3060 
3061         try {
3062             return imagepipe.copyImage(this, img, x, y, bg, observer);
3063         } catch (InvalidPipeException e) {
3064             revalidateAll();
3065             try {
3066                 return imagepipe.copyImage(this, img, x, y, bg, observer);
3067             } catch (InvalidPipeException e2) {
3068                 
3069                 
3070                 
3071                 return false;
3072             }
3073         } finally {
3074             surfaceData.markDirty();
3075         }
3076     }
3077 
3078     
3079 
3080 
3081 
3082     public boolean drawImage(Image img,
3083                              int dx1, int dy1, int dx2, int dy2,
3084                              int sx1, int sy1, int sx2, int sy2,
3085                              ImageObserver observer) {
3086         return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
3087                          observer);
3088     }
3089 
3090     
3091 
3092 
3093 
3094     public boolean drawImage(Image img,
3095                              int dx1, int dy1, int dx2, int dy2,
3096                              int sx1, int sy1, int sx2, int sy2,
3097                              Color bgcolor, ImageObserver observer) {
3098 
3099         if (img == null) {
3100             return true;
3101         }
3102 
3103         if (dx1 == dx2 || dy1 == dy2 ||
3104             sx1 == sx2 || sy1 == sy2)
3105         {
3106             return true;
3107         }
3108 
3109         if (((sx2 - sx1) == (dx2 - dx1)) &&
3110             ((sy2 - sy1) == (dy2 - dy1)))
3111         {
3112             
3113             int srcX, srcY, dstX, dstY, width, height;
3114             if (sx2 > sx1) {
3115                 width = sx2 - sx1;
3116                 srcX = sx1;
3117                 dstX = dx1;
3118             } else {
3119                 width = sx1 - sx2;
3120                 srcX = sx2;
3121                 dstX = dx2;
3122             }
3123             if (sy2 > sy1) {
3124                 height = sy2-sy1;
3125                 srcY = sy1;
3126                 dstY = dy1;
3127             } else {
3128                 height = sy1-sy2;
3129                 srcY = sy2;
3130                 dstY = dy2;
3131             }
3132             return copyImage(img, dstX, dstY, srcX, srcY,
3133                              width, height, bgcolor, observer);
3134         }
3135 
3136         try {
3137             return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2,
3138                                           sx1, sy1, sx2, sy2, bgcolor,
3139                                           observer);
3140         } catch (InvalidPipeException e) {
3141             revalidateAll();
3142             try {
3143                 return imagepipe.scaleImage(this, img, dx1, dy1, dx2, dy2,
3144                                               sx1, sy1, sx2, sy2, bgcolor,
3145                                               observer);
3146             } catch (InvalidPipeException e2) {
3147                 
3148                 
3149                 
3150                 return false;
3151             }
3152         } finally {
3153             surfaceData.markDirty();
3154         }
3155     }
3156 
3157     
3158 
3159 
3160 
3161 
3162 
3163 
3164 
3165 
3166 
3167 
3168 
3169 
3170 
3171 
3172 
3173 
3174 
3175     public boolean drawImage(Image img,
3176                              AffineTransform xform,
3177                              ImageObserver observer) {
3178 
3179         if (img == null) {
3180             return true;
3181         }
3182 
3183         if (xform == null || xform.isIdentity()) {
3184             return drawImage(img, 0, 0, null, observer);
3185         }
3186 
3187         try {
3188             return imagepipe.transformImage(this, img, xform, observer);
3189         } catch (InvalidPipeException e) {
3190             revalidateAll();
3191             try {
3192                 return imagepipe.transformImage(this, img, xform, observer);
3193             } catch (InvalidPipeException e2) {
3194                 
3195                 
3196                 
3197                 return false;
3198             }
3199         } finally {
3200             surfaceData.markDirty();
3201         }
3202     }
3203 
3204     public void drawImage(BufferedImage bImg,
3205                           BufferedImageOp op,
3206                           int x,
3207                           int y)  {
3208 
3209         if (bImg == null) {
3210             return;
3211         }
3212 
3213         try {
3214             imagepipe.transformImage(this, bImg, op, x, y);
3215         } catch (InvalidPipeException e) {
3216             revalidateAll();
3217             try {
3218                 imagepipe.transformImage(this, bImg, op, x, y);
3219             } catch (InvalidPipeException e2) {
3220                 
3221                 
3222                 
3223             }
3224         } finally {
3225             surfaceData.markDirty();
3226         }
3227     }
3228 
3229     
3230 
3231 
3232 
3233     public FontRenderContext getFontRenderContext() {
3234         if (cachedFRC == null) {
3235             int aahint = textAntialiasHint;
3236             if (aahint == SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT &&
3237                 antialiasHint == SunHints.INTVAL_ANTIALIAS_ON) {
3238                 aahint = SunHints.INTVAL_TEXT_ANTIALIAS_ON;
3239             }
3240             
3241             AffineTransform tx = null;
3242             if (transformState >= TRANSFORM_TRANSLATESCALE) {
3243                 if (transform.getTranslateX() == 0 &&
3244                     transform.getTranslateY() == 0) {
3245                     tx = transform;
3246                 } else {
3247                     tx = new AffineTransform(transform.getScaleX(),
3248                                              transform.getShearY(),
3249                                              transform.getShearX(),
3250                                              transform.getScaleY(),
3251                                              0, 0);
3252                 }
3253             }
3254             cachedFRC = new FontRenderContext(tx,
3255              SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING, aahint),
3256              SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,
3257                                 fractionalMetricsHint));
3258         }
3259         return cachedFRC;
3260     }
3261     private FontRenderContext cachedFRC;
3262 
3263     
3264 
3265 
3266 
3267 
3268 
3269 
3270 
3271 
3272     public void dispose() {
3273         surfaceData = NullSurfaceData.theInstance;
3274         invalidatePipe();
3275     }
3276 
3277     
3278 
3279 
3280 
3281 
3282 
3283 
3284 
3285 
3286 
3287 
3288     public void finalize() {
3289         
3290     }
3291 
3292     
3293 
3294 
3295 
3296 
3297     public Object getDestination() {
3298         return surfaceData.getDestination();
3299     }
3300 
3301     
3302 
3303 
3304 
3305 
3306     @Override
3307     public Surface getDestSurface() {
3308         return surfaceData;
3309     }
3310 }